﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;

namespace DbSharp.Framework.Driver.FieldPersistence
{
    public class SqlServerFieldPersistence : IFieldPersistence
    {
        #region IFieldPersistence<SqlDbType> members


        public List<int> ListSupportedScalarDataType
        {
            get
            {
                var list = new List<int>();
                list.Add((int)SqlDbType.BigInt);
                list.Add((int)SqlDbType.Bit);
                list.Add((int)SqlDbType.Char);
                list.Add((int)SqlDbType.DateTime);
                list.Add((int)SqlDbType.Decimal);
                list.Add((int)SqlDbType.Float);
                list.Add((int)SqlDbType.Int);
                list.Add((int)SqlDbType.Money);
                list.Add((int)SqlDbType.NChar);
                list.Add((int)SqlDbType.NText);
                list.Add((int)SqlDbType.NVarChar);
                list.Add((int)SqlDbType.Real);
                list.Add((int)SqlDbType.UniqueIdentifier);
                list.Add((int)SqlDbType.SmallDateTime);
                list.Add((int)SqlDbType.SmallInt);
                list.Add((int)SqlDbType.SmallMoney);
                list.Add((int)SqlDbType.Text);
                list.Add((int)SqlDbType.Timestamp);
                list.Add((int)SqlDbType.TinyInt);
                list.Add((int)SqlDbType.VarChar);
                list.Add((int)SqlDbType.Date);
                list.Add((int)SqlDbType.Time);
                list.Add((int)SqlDbType.DateTime2);
                list.Add((int)SqlDbType.DateTimeOffset);
                list.Add((int)SqlDbType.VarChar);

                return list;
            }
        }

        public List<int> ListSupportedRecordsetDataType
        {
            get { return new List<int>(); }
        }

        public string ConvertToString(object value, int valueType)
        {
            var valueType1 = (SqlDbType)valueType;
            var exceptionFmt = "{0} type is not supported.";
            var exceptionMsg = string.Format(exceptionFmt, valueType1.ToString());
            if (!ListSupportedScalarDataType.Contains(valueType))
            {
                throw new NotSupportedException(exceptionMsg);
            }

            string result;
            switch (valueType1)
            {
                case SqlDbType.BigInt:
                case SqlDbType.Bit:
                case SqlDbType.Char:
                case SqlDbType.DateTime:
                case SqlDbType.Decimal:
                case SqlDbType.Float:
                case SqlDbType.Int:
                case SqlDbType.Money:
                case SqlDbType.NChar:
                case SqlDbType.NText:
                case SqlDbType.NVarChar:
                case SqlDbType.Real:
                case SqlDbType.UniqueIdentifier:
                case SqlDbType.SmallDateTime:
                case SqlDbType.SmallInt:
                case SqlDbType.SmallMoney:
                case SqlDbType.Text:
                case SqlDbType.Timestamp:
                case SqlDbType.TinyInt:
                case SqlDbType.VarChar:
                case SqlDbType.Date:
                case SqlDbType.Time:
                case SqlDbType.DateTime2:
                case SqlDbType.DateTimeOffset:
                    result = FieldPersistenceHelper.SafeConvertToString(value);
                    break;
                default:
                    throw new NotSupportedException(exceptionMsg);
            }
            return result;
        }

        public decimal RestoreStringToDecimal(string valueStr, int valueType)
        {
            var valueType1 = (SqlDbType)valueType;
            decimal result;
            switch (valueType1)
            {
                case SqlDbType.BigInt:
                case SqlDbType.Bit:
                case SqlDbType.Decimal:
                case SqlDbType.Float:
                case SqlDbType.Int:
                case SqlDbType.Money:
                case SqlDbType.Real:
                case SqlDbType.SmallInt:
                case SqlDbType.SmallMoney:
                case SqlDbType.TinyInt:
                    result = Convert.ToDecimal(valueStr);
                    break;
                default:
                    throw new NotSupportedException(string.Format("{0} type is not supported.", valueType1.ToString()));
            }
            return result;
        }

        public Devart.Data.Oracle.OracleNumber RestoreStringToLargeDecimal(string valueStr, int valueType)
        {
            var valueType1 = (SqlDbType)valueType;
            Devart.Data.Oracle.OracleNumber result;
            switch (valueType1)
            {
                case SqlDbType.BigInt:
                case SqlDbType.Bit:
                case SqlDbType.Decimal:
                case SqlDbType.Float:
                case SqlDbType.Int:
                case SqlDbType.Money:
                case SqlDbType.Real:
                case SqlDbType.SmallInt:
                case SqlDbType.SmallMoney:
                case SqlDbType.TinyInt:
                    result = Devart.Data.Oracle.OracleNumber.Parse(valueStr);
                    break;
                default:
                    throw new NotSupportedException(string.Format("{0} type is not supported.", valueType1.ToString()));
            }
            return result;
        }



        public int GetSpecificDbType(DbDataReader dataReader, int columnIndex)
        {
            //class: System.Data.SqlClient.SqlDataReader
            //method: public override string GetDataTypeName(int i)

            //var method = dataReader.GetType().GetMethod("GetDataTypeName");
            //var parameters = new object[] { columnIndex };
            //var typeName = (string)method.Invoke(dataReader, parameters);
            //return (int)Enum.Parse(typeof(SqlDbType), typeName, true);

            var reader = (System.Data.SqlClient.SqlDataReader)dataReader;
            var typeName = reader.GetDataTypeName(columnIndex);
            return (int)Enum.Parse(typeof(SqlDbType), typeName, true);
        }


 


        public int GetSpecificDbType(DbParameter dbParam)
        {

            var typ = ((SqlParameter)dbParam).SqlDbType;
            return (int)typ;
        }

        public int NumberTypeWhenParseLiteral
        {
            get { return (int)(SqlDbType.Decimal); }
        }

        public bool IsStringType(int valueType)
        {
            bool result = false;
            var valueType1 = (SqlDbType)valueType;
            switch (valueType1)
            {
                case SqlDbType.Char:
                case SqlDbType.NChar:
                case SqlDbType.NText:
                case SqlDbType.NVarChar:
                case SqlDbType.Text:
                case SqlDbType.VarChar:
                    result = true;
                    break;
                default:
                    result = false;
                    break;
            }
            return result;
        }

        #endregion
    }

}
